import serial
import serial.tools.list_ports
import time
import threading
from datetime import datetime
from typing import Dict, Set, Optional, List
import sys

class FastSerial2500000:
    def __init__(self, baudrate: int = 2500000,  # 改为默认2.5M波特率（2500000）
                 timeout: float = 0.001,
                 scan_interval: float = 0.0001,  # 100微秒扫描（不改动，保证快速发现串口）
                 hex_separator: str = ' ',
                 send_duration: float = 0.004):  # 新增：发送0x1A的持续时间（4ms）
        # 串口核心参数（固定8N1，2.5M波特率）
        self.baudrate = baudrate
        self.bytesize = serial.EIGHTBITS
        self.parity = serial.PARITY_NONE
        self.stopbits = serial.STOPBITS_ONE
        self.timeout = timeout
        self.scan_interval = scan_interval
        self.hex_sep = hex_separator
        self.send_duration = send_duration  # 4ms发送窗口（可微调）

        # 存储管理（保持多串口独立资源）
        self.active_ports: Dict[str, serial.Serial] = {}
        self.known_ports: Set[str] = set()
        self.is_running = False
        
        # 功能配置修改：目标序列改为0x07→0x21，回复字节0x1A
        self.target1 = 0x07  # 目标字节1：0x07（不变）
        self.target2 = 0x21  # 目标字节2：改为0x21（原0x26）
        self.response_byte = 0x1A  # 回复字节：0x1A（不变）
        self.is_transparent = False  # 透传模式标志（改为False，4ms后自动开启）
        self.port_buffers: Dict[str, List[int]] = {}
        self.input_threads: Dict[str, Optional[threading.Thread]] = {}
        self.send_threads: Dict[str, Optional[threading.Thread]] = {}  # 新增：独立发送线程（避免阻塞接收）

        # 禁用日志，减少IO开销（2.5M波特率下更重要）
        if hasattr(serial, 'logger'):
            serial.logger.setLevel(50)

    def _get_time(self) -> str:
        """获取毫秒级时间戳（不变）"""
        return datetime.now().strftime("%H:%M:%S.%f")[:-3]

    def _scan_ports(self) -> List[str]:
        """快速扫描可用串口（不变）"""
        ports = []
        try:
            for port in serial.tools.list_ports.comports():
                ports.append(port.device)
        except Exception:
            pass
        return ports

    def _bytes_to_hex(self, data: bytes) -> str:
        """bytes→16进制字符串（不变）"""
        return self.hex_sep.join([f"{b:02X}" for b in data])

    def _hex_to_bytes(self, hex_str: str) -> Optional[bytes]:
        """16进制字符串→bytes（不变）"""
        clean_hex = hex_str.strip().replace(self.hex_sep, "").replace(" ", "")
        if len(clean_hex) % 2 != 0:
            print(f"\033[91m[{self._get_time()}] 错误：16进制字符串长度必须为偶数（输入：{hex_str}）\033[0m")
            return None
        try:
            return bytes.fromhex(clean_hex)
        except ValueError:
            print(f"\033[91m[{self._get_time()}] 错误：含非16进制字符（输入：{hex_str}）\033[0m")
            return None

    def _user_input_handler(self, port_name: str, ser: serial.Serial):
        """透传模式：用户输入处理（不变）"""
        print(f"\n=== {port_name} 4ms发送完成，进入透传模式 ===")
        print("规则说明：")
        print("1. 下位机上传数据将以16进制字符串实时显示（如：07 21 1A 12 34 AB）")
        print("2. 你输入16进制字符串（支持格式：12 34 AB 或 1234AB），按回车发送")
        print("3. 输入 'exit' 可退出透传模式（程序继续监视串口）")
        print("-" * 60)
        
        while self.is_running and self.is_transparent and port_name in self.active_ports:
            try:
                user_input = input(f"\033[92m[{port_name}] 输入16进制数据（或exit退出）：\033[0m")
                if user_input.strip().lower() == 'exit':
                    self.is_transparent = False
                    print(f"=== {port_name} 退出透传模式，恢复正常监视 ===")
                    break
                send_data = self._hex_to_bytes(user_input)
                if send_data:
                    ser.write(send_data)
                    print(f"[{self._get_time()}] [{port_name}] 发送成功：{self._bytes_to_hex(send_data)}（字节数：{len(send_data)}）")
            except serial.SerialException:
                print(f"\033[91m[{self._get_time()}] [{port_name}] 错误：串口已断开\033[0m")
                break
            except Exception as e:
                print(f"\033[91m[{self._get_time()}] 输入处理失败：{e}\033[0m")

    def _continuous_send_1A(self, port_name: str, ser: serial.Serial):
        """新增：4ms内连续发送0x1A（独立线程，不阻塞接收）"""
        start_time = time.perf_counter()  # 高精度计时（微秒级，确保4ms精度）
        send_count = 0  # 统计发送次数
        batch_size = 50  # 批量发送大小（减少write调用次数，提升效率）
        response_bytes = bytes([self.response_byte] * batch_size)  # 预生成批量发送数据

        print(f"\033[93m[{self._get_time()}] [{port_name}] 开始4ms内连续发送0x1A...\033[0m")

        try:
            # 循环发送，直到超过4ms
            while self.is_running and port_name in self.active_ports:
                # 计算已耗时（秒）
                elapsed = time.perf_counter() - start_time
                if elapsed >= self.send_duration:
                    break  # 超过4ms，停止发送

                # 发送数据（非阻塞，2.5M波特率下批量发送更高效）
                try:
                    # 检查串口是否可写，避免缓冲区溢出
                    if ser.out_waiting < 1024:  # 缓冲区剩余空间>1024字节才发送
                        ser.write(response_bytes)
                        send_count += batch_size
                except serial.SerialException:
                    print(f"\033[91m[{self._get_time()}] [{port_name}] 发送失败：串口断开\033[0m")
                    break

            # 发送完成，统计结果
            total_elapsed = (time.perf_counter() - start_time) * 1000  # 转为毫秒
            print(f"\033[93m[{self._get_time()}] [{port_name}] 4ms发送结束！")
            print(f"[统计] 实际耗时：{total_elapsed:.2f}ms，发送0x1A总次数：{send_count}\033[0m")

        finally:
            # 无论发送是否成功，4ms后都进入透传模式
            if self.is_running and port_name in self.active_ports:
                self.is_transparent = True
                # 启动透传输入线程
                self.input_threads[port_name] = threading.Thread(
                    target=self._user_input_handler,
                    args=(port_name, ser),
                    daemon=True
                )
                self.input_threads[port_name].start()
            # 清理发送线程
            if port_name in self.send_threads:
                del self.send_threads[port_name]

    def _recv_data_handler(self, port_name: str, ser: serial.Serial):
        """修改：检测0x07→0x21后启动4ms连续发送"""
        self.port_buffers[port_name] = []
        print(f"\n[{self._get_time()}] [{port_name}] 开始监听（参数：2500000 8N1）")
        print(f"[{port_name}] 等待检测序列：07（0x07）→ 21（0x21）（支持连接后立即发送/分开发送）")
        
        while self.is_running and port_name in self.active_ports:
            try:
                if ser.in_waiting > 0:
                    recv_bytes = ser.read(ser.in_waiting)
                    current_time = self._get_time()
                    buffer = self.port_buffers[port_name]

                    # 未进入透传模式：检测目标序列0x07→0x21
                    if not self.is_transparent:
                        for byte in recv_bytes:
                            buffer.append(byte)
                            buffer = buffer[-2:]  # 只保留最近2字节
                            self.port_buffers[port_name] = buffer
                            print(f"[{current_time}] [{port_name}] 接收：{byte:02X}")

                        # 检测目标序列（0x07→0x21），且未启动发送线程
                        if (len(buffer) == 2 and buffer[0] == self.target1 and buffer[1] == self.target2
                                and port_name not in self.send_threads):
                            target_hex = f"{self.target1:02X} {self.target2:02X}"
                            print(f"\033[93m[{current_time}] [{port_name}] 检测到目标序列：{target_hex}\033[0m")
                            
                            # 启动独立发送线程（4ms内连续发0x1A），不阻塞接收
                            self.send_threads[port_name] = threading.Thread(
                                target=self._continuous_send_1A,
                                args=(port_name, ser),
                                daemon=True
                            )
                            self.send_threads[port_name].start()

                    # 透传模式：直接显示所有数据（不变）
                    else:
                        recv_hex_str = self._bytes_to_hex(recv_bytes)
                        print(f"\033[94m[{current_time}] [{port_name}] 透传接收：{recv_hex_str}\033[0m")

            except serial.SerialException:
                print(f"\n\033[91m[{current_time}] [{port_name}] 错误：串口已断开连接\033[0m")
                break
            except Exception as e:
                print(f"\n\033[91m[{current_time}] [{port_name}] 读取错误：{e}\033[0m")
                break
        
        # 清理资源（新增发送线程清理）
        self._close_port(port_name)
        self.is_transparent = False
        if port_name in self.port_buffers:
            del self.port_buffers[port_name]
        if port_name in self.input_threads:
            del self.input_threads[port_name]
        if port_name in self.send_threads:
            del self.send_threads[port_name]

    def _open_port(self, port_name: str) -> bool:
        """修改：适配2.5M波特率，优化串口配置"""
        try:
            ser = serial.Serial(
                port=port_name,
                baudrate=self.baudrate,  # 2500000波特率
                bytesize=self.bytesize,
                parity=self.parity,
                stopbits=self.stopbits,
                timeout=self.timeout,
                dsrdtr=False,
                rtscts=False,
                xonxoff=False,
                writeTimeout=0.001,
                interCharTimeout=0.0001,  # 字符间超时缩短到100微秒（适配高速波特率）
                exclusive=True
            )
            
            if ser.is_open:
                self.active_ports[port_name] = ser
                self.known_ports.add(port_name)
                
                recv_thread = threading.Thread(
                    target=self._recv_data_handler,
                    args=(port_name, ser),
                    daemon=True
                )
                recv_thread.start()
                
                print(f"\033[92m[{self._get_time()}] 成功：连接串口 {port_name}（2500000 8N1）\033[0m")
                return True
        except Exception as e:
            # 2.5M波特率可能不被硬件支持，添加友好提示
            print(f"\033[91m[{self._get_time()}] 失败：连接串口 {port_name}（错误：{e}）")
            print(f"[提示] 2500000波特率为非常规波特率，请确认串口硬件（如USB转串口模块）支持！\033[0m")
        return False

    def _close_port(self, port_name: str):
        """不变：快速关闭串口"""
        try:
            if port_name in self.active_ports:
                ser = self.active_ports[port_name]
                if ser.is_open:
                    ser.close()
                del self.active_ports[port_name]
                print(f"[{self._get_time()}] 信息：关闭串口 {port_name}")
        except Exception:
            pass

    def _monitor_ports(self):
        """修改：启动信息更新为2.5M波特率"""
        print(f"[{self._get_time()}] 启动：快速串口监视器（扫描间隔：100微秒）")
        print(f"[配置] 波特率={self.baudrate}（2.5M），数据位={self.bytesize}，校验位=N，停止位={self.stopbits}")
        print(f"[功能] 1. 自动连接串口  2. 检测0x07→0x21后4ms内连续发0x1A  3. 超时后进入16进制透传")
        print("-" * 80)
        
        initial_ports = self._scan_ports()
        for port in initial_ports:
            if port not in self.known_ports:
                self._open_port(port)
        
        while self.is_running:
            current_ports = self._scan_ports()
            
            for port in current_ports:
                if port not in self.known_ports:
                    print(f"\n\033[95m[{self._get_time()}] 发现：新串口 {port}\033[0m")
                    self._open_port(port)
            
            for port in list(self.known_ports):
                if port not in current_ports and port in self.active_ports:
                    print(f"\n\033[91m[{self._get_time()}] 断开：串口 {port}\033[0m")
                    self._close_port(port)
            
            time.sleep(self.scan_interval)

    def start(self):
        """不变：程序启动入口"""
        self.is_running = True
        monitor_thread = threading.Thread(target=self._monitor_ports)
        monitor_thread.daemon = False
        monitor_thread.start()
        
        try:
            while self.is_running:
                time.sleep(0.1)
        except KeyboardInterrupt:
            print("\n\n\033[91m[中断] 正在停止监视器...\033[0m")
            self.stop()

    def stop(self):
        """修改：新增发送线程停止清理"""
        self.is_running = False
        self.is_transparent = False
        # 关闭所有活跃串口
        for port_name in list(self.active_ports.keys()):
            self._close_port(port_name)
        # 清空所有缓存和线程
        self.port_buffers.clear()
        self.input_threads.clear()
        self.send_threads.clear()  # 清理发送线程
        print(f"[{self._get_time()}] 停止：串口监视器已完全关闭")

def main():
    # 修改：默认波特率改为2500000，命令行参数仍支持自定义
    if len(sys.argv) > 1:
        try:
            baudrate = int(sys.argv[1])
            print(f"[提示] 自定义波特率：{baudrate}（默认：2500000 8N1）")
        except:
            print("命令行参数错误！格式：python serial_2500000.py [波特率]")
            print("示例：python serial_2500000.py 115200（如需修改波特率）")
            return
    else:
        baudrate = 2500000  # 默认2.5M波特率
    
    # 检查依赖库
    try:
        import serial
        import serial.tools.list_ports
    except ImportError:
        print("缺少依赖库！请运行：pip install pyserial")
        sys.exit(1)
    
    # 启动监视器
    monitor = FastSerial2500000(baudrate=baudrate)
    try:
        monitor.start()
    except Exception as e:
        print(f"[错误] 监视器启动失败：{e}")
        monitor.stop()

if __name__ == "__main__":
    main()